﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.IO.Compression;

namespace Util.Net
{
    public sealed class Download
    {
        private Download()
        {
        }


        public static void DownloadFile(string address, string fileName)
        {
            MemoryStream data = DownloadData(address);
            using (FileStream fs = System.IO.File.Create(fileName))
            {
                fs.Write(data.GetBuffer(), 0, (int)data.Length);
                fs.Flush();
            }
        }


        public static MemoryStream DownloadData(string address)
        {
            int errorCount = 0;
            while (true)
            {
                try
                {
                    using (System.Net.WebClient c = new System.Net.WebClient())
                    {
                        c.Headers["User-Agent"] = "Mozilla/4.0";
                        c.Headers["Accept-Encoding"] = "gzip, deflate";
                        byte[] data = c.DownloadData(address);
                        if (string.IsNullOrEmpty(c.ResponseHeaders["Content-Encoding"]))
                        {
                            return new MemoryStream(data);
                        }

                        try
                        {
                            using (Stream InputStream = new MemoryStream(data))
                            {
                                using (Stream DecompressStream = CreateDecompressor(c.ResponseHeaders["Content-Encoding"], InputStream))
                                {
                                    return Decompress(DecompressStream);
                                }
                            }
                        }
                        catch
                        {
                            return new MemoryStream(data);
                        }
                    }
                }
                catch (System.Net.WebException ex)
                {
                    errorCount++;
                    if (errorCount >= 3)
                    {
                        throw new DownloadException("Couldn't download file", ex);
                    }
                }
            }
        }


        private static Stream CreateDecompressor(string ContentEncoding, Stream data)
        {
            if(string.IsNullOrEmpty(ContentEncoding))
            {
                throw new ArgumentNullException("ContentEncoding");
            }

            ContentEncoding = ContentEncoding.ToUpperInvariant();
            if (ContentEncoding.Contains("GZIP"))
            {
                return new GZipStream(data, CompressionMode.Decompress);
            }
            else if (ContentEncoding.Contains("DEFLATE"))
            {
                return new DeflateStream(data, CompressionMode.Decompress);
            }
            throw new ArgumentException("Unknown compression method", "ContentEncoding");
        }


        private static MemoryStream Decompress(Stream DecompressStream)
        {
            MemoryStream streamOutput = new MemoryStream();
            try
            {
                byte[] readBuffer = new byte[4096];
                int i;
                while ((i = DecompressStream.Read(readBuffer, 0, readBuffer.Length)) != 0)
                {
                    streamOutput.Write(readBuffer, 0, i);
                }
                streamOutput.Position = 0;
                return streamOutput;
            }
            catch
            {
                streamOutput.Close();
                throw;
            }
        }
    }
}
